﻿using System;

namespace PhiStore.Policies
{
    /// <summary>
    /// This class must accompany any object added to the PhiStore
    /// </summary>
    [Serializable]
    public class Policy
    {
        /* Garbage collection */
        private bool mayBeGC = true;
        private ulong idleThreshold = 60 * 60 * 1000; //1 hour

        /* number for replication policy */
        private uint replicationNumber = 1;

        /* Allowed operations */
        private bool mayModify = true;
        private bool mayDelete = true;
        private bool mayAppend = true;
        private bool mayPop = true;

        /* Special behavior */
        private bool atomicity = true;
        private bool fastReturn = false;

        private string YesNo(bool input)
        {
            return input ? "Yes" : "No";
        }

        /// <summary>
        /// Presents options for this policy as a string
        /// </summary>
        /// <returns>String representation of this policy</returns>
        public override string ToString()
        {
            return "[MayGarbageCollect: " + YesNo(mayBeGC) + ", " +
                    "IdleThreshold: " + (idleThreshold / 1000) + "sec , " +
                    "ReplicationNumber: " + replicationNumber + ", " +
                    "EnforceAtomicity: " + YesNo(atomicity) + ", " +
                    "FastReturn: " + YesNo(fastReturn) + ", " +
                    "MayModify: " + YesNo(mayModify) + ", " +
                    "MayDelete: " + YesNo(mayDelete) + ", " +
                    "MayAppend: " + YesNo(mayAppend) + ", " +
                    "MayPop: " + YesNo(mayPop) + " (Prefetchable: " + YesNo(Prefetchable) + ")]";
        }

        /// <summary>
        /// Constructor
        /// </summary>
        public Policy() { }

        /// <summary>
        /// Dictates on how many PhiServers should have a copy of the object
        /// </summary>
        public uint ReplicationNumber
        {
            get { return replicationNumber; }
            set
            {
                if (value == 0)
                {
                    throw new ArgumentException("Replication number should be greater than 0");
                }
                replicationNumber = value;
            }
        }

        /// <summary>
        /// Modifying the object should use 2PC in order to ensure atomicity
        /// </summary>
        public bool EnforceAtomicity
        {
            get { return atomicity; }
            set { atomicity = value; }
        }

        /// <summary>
        /// Objects using this policy may be garbage collected
        /// </summary>
        public bool MayGarbageCollect
        {
            get { return mayBeGC; }
            set { mayBeGC = value; }
        }

        /// <summary>
        /// If garbage collection is permitted, this threshold (in millisecondsTimeout) dictate when an object is considered unused
        /// If garbage collection is not permitted, this threshold dictates when the object may be demoted to a slower storage device
        /// </summary>
        public ulong IdleThreshold
        {
            get { return idleThreshold; }
            set { idleThreshold = value; }
        }

        /// <summary>
        /// Modifying operations are permitted/disallowed
        /// </summary>
        public bool MayModify
        {
            get { return mayModify; }
            set { mayModify = value; }
        }

        /// <summary>
        /// Complete object deletion as well as index deletion is permitted/disallowed
        /// </summary>
        public bool MayDelete
        {
            get { return mayDelete; }
            set { mayDelete = value; }
        }

        /// <summary>
        /// Dictates whether or not append operations are allowed
        /// </summary>
        public bool MayAppend
        {
            get { return mayAppend; }
            set { mayAppend = value; }
        }

        /// <summary>
        /// Dictates whether or not pop operations are allowed
        /// </summary>
        public bool MayPop
        {
            get { return mayPop; }
            set { mayPop = value; }
        }

        /// <summary>
        /// Dictatest whether or not the Coordinating PhiServer for any particular object should be contacted for a up-to-date version
        /// If this setting is enabled, any "random" copy will be returned if the PhiServer has the object/elements in question
        /// </summary>
        public bool FastReturn
        {
            get { return fastReturn; }
            set { fastReturn = value; }
        }


        /// <summary>
        /// Determines if the policy enables the object to be prefetchable.
        /// </summary>
        public bool Prefetchable
        {
            get
            {
                bool prefetchable = fastReturn;
                prefetchable |= !mayModify && !mayDelete && !mayPop;
                return prefetchable;
            }
        }



        /// <summary>
        /// Makes a exact copy of the policy
        /// </summary>
        /// <returns>a copy</returns>
        public Policy Copy()
        {
            Policy result = new Policy();
            result.EnforceAtomicity = atomicity;
            result.FastReturn = fastReturn;
            result.IdleThreshold = idleThreshold;
            result.MayAppend = mayAppend;
            result.MayGarbageCollect = mayBeGC;
            result.MayDelete = mayDelete;
            result.MayModify = mayModify;
            result.MayPop = mayPop;
            result.ReplicationNumber = replicationNumber;

            return result;
        }

    }
}
